﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Lacrima.Framework.Infrastructure
{
    /// <summary>
    /// 坐标系类
    /// 新增：仇士龙，2017年3月27日20:09:42
    /// </summary>
    public static class CoordinateExtension
    {
        /// <summary>
        /// 坐标转换，将十进制度转换为度时分秒的形式
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private static CoordinateModel ParseDegree(double source)
        {
            return CoordinateModel.Parse(source);
        }

        /// <summary>
        /// 将十进制纬度转换为坐标制纬度
        /// 方法参照：http://blog.sina.com.cn/s/blog_7b0807af0101lh3n.html
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>System.String.</returns>
        public static string ToLatitude(double source, int digits = 0)
        {
            string latitude = string.Format("{0}{1}", GetLatitudeDirection(source), ParseDegree(source).ToLatitude(digits));
            return latitude;
        }

        /// <summary>
        /// 将十进制经度转换为坐标制经度
        /// 方法参照：http://blog.sina.com.cn/s/blog_7b0807af0101lh3n.html
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>System.String.</returns>
        public static string ToLongitude(double source, int digits = 0)
        {
            string direction = Arithmetic.IsPositive(source) ? "E" : "W";
            string longitude = string.Format("{0}{1}", direction, ParseDegree(source).ToLongitude(digits));
            return longitude;
        }

        /// <summary>
        /// 获取纬度方向
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>System.String.</returns>
        public static string GetLatitudeDirection(double source)
        {
            string direction = Arithmetic.IsPositive(source) ? "N" : "S";
            return direction;
        }

        /// <summary>
        /// 获取经度方向
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>System.String.</returns>
        public static string GetLongitudeDirection(double source)
        {
            string direction = Arithmetic.IsPositive(source) ? "E" : "W";
            return direction;
        }

        /// <summary> 
        /// 度分秒经纬度和数字经纬度转换
        /// </summary> 
        /// <param name="digitalDegree">度分秒经纬度，秒后带小数 格式为:E1202030.5,N302530.2</param> 
        /// <return>数字经纬度</return> 
        public static double DegreeToDecimal(string degrees)
        {
            const double num = 60;
            double digitalDegree = 0.0;
            //判断是否是经度 包含E或W 
            if (degrees.Contains("E") || degrees.Contains("W"))
            {
                string degree = degrees.Substring(1, 3);//度 
                digitalDegree += Convert.ToDouble(degree);
                string minute = degrees.Substring(4, 2);//分 
                digitalDegree += ((Convert.ToDouble(minute)) / num);
                string second = degrees.Substring(6, degrees.Length - 6);//秒 
                digitalDegree += (Convert.ToDouble(second) / (num * num));
            }
            //如果是纬度 
            if (degrees.Contains("N") || degrees.Contains("S"))
            {
                string degree = degrees.Substring(1, 2);//度 
                digitalDegree += Convert.ToDouble(degree);
                string minute = degrees.Substring(3, 2);//分 
                digitalDegree += ((Convert.ToDouble(minute)) / num);
                string second = degrees.Substring(5, degrees.Length - 5);//秒 
                digitalDegree += (Convert.ToDouble(second) / (num * num));
            }

            return digitalDegree;
        }

        public static string RoundLatitude(string latitude, int digits = 0)
        {
            double degree;
            if (!string.IsNullOrEmpty(latitude) && double.TryParse(latitude.Substring(1), out degree))
            {
                char direction = latitude.First();
                return string.Format("{0}{1}", direction, Math.Round(degree, digits, MidpointRounding.AwayFromZero));
            }
            return null;
        }

        public static string RoundLongitude(string longitude, int digits = 0)
        {
            double degree;
            if (!string.IsNullOrEmpty(longitude) && double.TryParse(longitude.Substring(1), out degree))
            {
                char direction = longitude.First();
                return string.Format("{0}{1:0000000}", direction, Math.Round(degree, digits, MidpointRounding.AwayFromZero));
            }
            return null;
        }
    }

    internal class CoordinateModel
    {
        public int Degree { get; set; }
        public int Minute { get; set; }
        public double Second { get; set; }

        public CoordinateModel(int degree, int minute, double second)
        {
            this.Degree = degree;
            this.Minute = minute;
            this.Second = second;
        }

        /// <summary>
        /// 坐标转换，将十进制度转换为度时分秒的形式
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static CoordinateModel Parse(double source)
        {
            if (!double.IsNaN(source))
            {
                double degree = Math.Abs(source);
                double minute = Arithmetic.GetNumberLeftOffsetTwoDigtal(degree) * 60 / 100;
                double second = Arithmetic.GetNumberLeftOffsetTwoDigtal(minute) * 60 / 100;
                return new CoordinateModel((int)degree, (int)minute, second);
            }
            return null;
        }
        /// <summary>
        /// To the latitude.
        /// </summary>
        /// <param name="digits">The digits.</param>
        /// <returns>System.String.</returns>
        public string ToLatitude(int digits = 0)
        {
            this.Revise(digits);
            string second = this.Second.ToString(string.Format("f{0}", digits)).PadLeft(digits == 0 ? 2 : digits + 3, '0');
            return string.Format("{0:00}{1:00}{2:00}", Degree, Minute, second);
        }

        /// <summary>
        /// To the longitude.
        /// </summary>
        /// <param name="digits">The digits.</param>
        /// <returns>System.String.</returns>
        public string ToLongitude(int digits = 0)
        {
            this.Revise(digits);
            string second = this.Second.ToString(string.Format("f{0}", digits)).PadLeft(digits == 0 ? 2 : digits + 3, '0');
            return string.Format("{0:000}{1:00}{2:00}", Degree, Minute, second);
        }

        protected virtual void Revise(int digits = 0)
        {
            int minuteAdd, degreeAdd;
            this.Second = Math.Round(Second, digits, MidpointRounding.AwayFromZero);
            minuteAdd = ((int)this.Second) / 60;
            this.Second %= 60;
            this.Minute += minuteAdd;
            degreeAdd = this.Minute / 60;
            this.Minute %= 60;
            this.Degree += degreeAdd;
        }
    }
}
